package mornd.test3;

import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.*;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * @author: mornd
 * @dateTime: 2023/5/10 - 18:16
 * 模拟 boot 启动发布的事件
 * 启动参数：--server.port=8080 debug
 */
public class App {

    public static void main(String[] args) throws Exception {
        SpringApplication spring = new SpringApplication();

        // 添加初始化器
        spring.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
            @Override
            public void initialize(ConfigurableApplicationContext applicationContext) {
                System.out.println("初始化器调用：" + applicationContext);
            }
        });

        System.out.println("2、封装启动 args");
        DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);

        System.out.println("8、创建容器");
        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);

        System.out.println("9、准备容器");
        System.out.println("回调所有初始化器");
        for (ApplicationContextInitializer initializer : spring.getInitializers()) {
            initializer.initialize(context);
        }

        System.out.println("10、加载 bean 定义");

        // 注解配置类 方式添加 beanDefinition
        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context.getDefaultListableBeanFactory());
        reader.register(Config.class);

        //region 其它方式添加 beanDefinition
        // xml 方式添加 beanDefinition
        XmlBeanDefinitionReader reader2 = new XmlBeanDefinitionReader(context.getDefaultListableBeanFactory());
        reader2.loadBeanDefinitions(new ClassPathResource("bean02.xml"));

        // 扫包 方式添加 beanDefinition
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context.getDefaultListableBeanFactory());
        scanner.scan("mornd.beans");
        //endregion

        System.out.println("11、refresh");
        context.refresh();

        //region print beanName
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println("name：" + name + " 来源：" + context.getBeanFactory().getBeanDefinition(name).getResourceDescription());
        }
        //endregion


        System.out.println("12、执行 runner");

        //region runner
        context.getBeansOfType(CommandLineRunner.class).forEach((k, v) -> {
            try {v.run(args);} catch (Exception e) {}
        });
        context.getBeansOfType(ApplicationRunner.class).forEach((k, v) -> {
            try {v.run(arguments);} catch (Exception e) {}
        });
        //endregion

    }

    private static GenericApplicationContext createApplicationContext(WebApplicationType type) {
        switch (type) {
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            case NONE:
                return new AnnotationConfigApplicationContext();
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            default:
                throw new RuntimeException("容器创建失败");
        }
    }

    static class Bean1 {}

    @Configuration
    static class Config {

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        // 注册 tomcat 服务器
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory(8080);
        }

        @Bean
        public CommandLineRunner runner() {
            return args -> System.out.println("CommandLineRunner回调：" + Arrays.toString(args));
        }

        @Bean
        public ApplicationRunner runner2() {
            return args -> {
                System.out.println("ApplicationRunner 回调1：" + args.getOptionNames());
                System.out.println("ApplicationRunner 回调2：" + Arrays.toString(args.getSourceArgs()));
                System.out.println("ApplicationRunner 回调3：" + args.getNonOptionArgs());
            };
        }
    }
}
